<?php
/**
 * Template instance.
 * <p>Currently, it's only able to render templates, not to build them
 * <p>Usage :</p>
 * <code>//read the template file :
 * $str=file_get_contents($file);
 * // build the template instance :
 * $tpl=new djangoTpl($str);
 * // Renders it with some data
 * echo $tpl->render($data);</code>
 * @uses dataPath
 * Django's templating engine (partial) PHP implementation
 * @link http://djangoproject.com Django
 * this file is from a webappkit package (kit)
 * @link http://webappkit.net
 * @package djtpl
 * @author J.Ducastel <nospam0@ducastel.name>
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 */
class DjTplTemplate {
/*------------------------------------------------------------------------------
                                                                     constructor
------------------------------------------------------------------------------*/
    /**
    * constructor alias
    * @access
    */
    function DjTplTemplate(&$str) {
        $this->__construct($str);
    }/**/

    /**
    * "real" constructor
    * @access public
    * @param string $str
    */
    function __construct(&$str) {
        $this->_buildFromString($str);
    }

    /**
    * returns a template from a file's content
    * @static
    * @param string $filename
    * @return djtplTemplate
    */
    function & getFromFile($filename) {
        if (!file_exists($filename)) {
            $f=false;
            return $f;
        }
        $str=join('',file($filename));
        return new DjTplTemplate($str);
    }
/*------------------------------------------------------------------------------
                                                                  public methods
------------------------------------------------------------------------------*/
    /**
    * Render's template with some data, as a string
    * @param array $data
    * @access public
    * @return string
    */
    function render($data=null) {
        // is the template extending another ?
        if ($this->parent) {
            //$rendered.='<p>extending '.$this->parent.'</p>';
            // searching parent within self storage
            if (!$this->storage
            or !$parent=$this->storage->get($this->parent)) {
                trigger_error("parent template not found ({$this->parent})");
                return false;
            }
            // overriding parent blocks with self blocks
            // echo '<pre>'; print_r($parent->blocks); exit;
            // echo '<pre>'; print_r($this); exit;
            // echo '<pre>'; print_r(array_keys($this->blocks)); exit;
            $parent->extend($this);
            // echo '<pre>'; print_r($context); exit;
            // rendering extended parent
            return $parent->render($data);
        } else {
            // building context
            if (is_a($data,'DjTplContext')) {
                $context=&$data;
            } else
                $context=&new DjTplContext($data);
            // rendering
            $rendered='';
            // looping nodes
            for ($n=0; $n<count($this->nodes); $n++) {
                $rendered.=$this->nodes[$n]->render($context);
            }
        }
        return $rendered;
    }

    /**
     * extend a template by overriding self blocks with child blocks
     * @access public
     * @param DjTplTemplate $child
     * @return bool
     */
    function extend($child) {
        if (!is_a($child,'DjTplTemplate'))
            return false;
        // echo '<pre>'; print_r($child->blocks);// exit;
        /*foreach (array_keys($child->blocks) as $name) {
            $this->blocks[$name]=$child->blocks[$name];
            //$this->blocks[$name]->setTemplate($this);
        }*/
        foreach ($child->blocks as $name => $childBlock) {
            $block=&$this->blocks[$name];
            $block=$childBlock;
            // echo "<p>overriding block $name</p>";
        }
        return true;
    }

    /**
     * sets storage (which will be used for template inheritance)
     * @access public
     * @param DjTplStorage $storage
     * @return bool
     */
    function setStorage($storage) {
        if (!is_a($storage,'DjTplStorage'))
            return false;
        $this->storage=&$storage;
        return true;
    }

    /**
     * get storage the template came from
     * @access public
     * @return DjTplStorage
     */
    function & getStorage() {
        return $this->storage;
    }

    /**
    * @var array djangoTplNode instances
    */
    var $nodes=array();

    /**
     * @var string parent template name if relevant
     */
    var $parent;

    /**
     * @var DjTplStorage reference to template storage, which may be used for inheritance
     */
    var $storage;

    /**
     * @var array references to named block nodes name => node
     */
    var $blocks=array();
/*------------------------------------------------------------------------------
                                                                 private methods
------------------------------------------------------------------------------*/
    /**
    * builds internal tree from string
    * @param string $str
    * @access private
    * @uses DjTplParser
    * @return bool
    */
    function _buildFromString(&$str) {
        // spliting into tokens
        $tokens=DjTplParser::tokenize($str);
        //echo '<pre>'; print_r($tokens);
        while ($node=&DjTplParser::tokensToNode($tokens,$this)) {
            // searching for 'extends' node
            if ($node->isTag('extends')) {
                $this->parent=$node->parent;
            } else if ($node->isTag('include')) {
                // echo '<pre>'; print_r($node);
            }
            // indexing blocks
            else if ($node->isTag('block') and $block=$node->isBlock()) {
                // echo "<p>block $block</p>";
                $this->blocks[$block]=&$node;
            }
            //echo '<pre>'; print_r($node);
            // adding node to tree
            $this->nodes[]=&$node;
        }
        return true;
    }/**/
}
